﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Cash5
{
    /// <summary>
    /// This class is like a controller that will do all calculation
    /// it uses lotto class as a model to fetch values
    /// </summary>
    public class PossibleNumbers
    {
        private int[] numbers;
        private Lotto lt;
        public List<int[]> allCombinations;
        public List<int[]> remainingCombinations;
        private int total;
        public PossibleNumbers(Lotto lt)
        {
            this.lt = lt;
            total = 0;
            compute();

        }
        /// <summary>
        /// Computes all combinations without repetition
        /// and updates model
        /// </summary>
        private void compute()
        {
            allCombinations = new List<int[]>();
            remainingCombinations = new List<int[]>();
            formNumbersArray(lt.From, lt.To);
            combinWithoutRep(lt.Digits, 0, numbers.Length, 0, new int[lt.Digits]);
            lt.PossibleCombinations = this.allCombinations.Count;
            lt.RemainingCombinations = this.remainingCombinations.Count;
        }
        /// <summary>
        /// If skiplist contains more numbers it will throw an exception
        /// </summary>
        /// <param name="numbers"></param>
        /// <param name="skipList"></param>
         private void checkSkipList(int[] numbers, List<int> skipList)
        {
            int count = 0;
            for (int i = 0; i < numbers.Length; i++)
            {
                if (skipList.Contains(numbers[i]))
                {
                    count++;
                }
            }
            if (count >= numbers.Length)
            {
                throw new CustomExceptionton("You have entered all possible numbers, so no combinations left");
            }
            else if (count < lt.Digits)
            {
                throw new CustomExceptionton("You have entered numbers to skip less than digits, which means it is not possible to generate combination from them. Enter at least numbers count equals to digits");
            }
        }
        private void formNumbersArray(int from, int to)
        {
           // combinations = new List<string>();
            numbers = new int[to + 1 - from];// because to is also inclusive
            for (int i = 0; i < to + 1 - from; i++)
            {
                numbers[i] = from + i;
            }
        }

        public void combinWithoutRep(int digits, int start, int total, int index, int[] nums)
        {
            if (index == digits)
            {
                addToPrint(nums);
            }
            else
            {
                for (int i = start; i < (total + index + 1) - digits; i++)
                {
                        nums[index] = numbers[i];
                        int nextInd = index + 1;
                        int nextStart = i + 1;
                        combinWithoutRep(digits, nextStart, total, nextInd, nums);
                }
            }
        }

        void Enumerate5CardCombinations()
        {
            int totalOutcomesEnumerated = 0;

            for (int card1 = 0; card1 < 48; card1++)
            {
                for (int card2 = card1 + 1; card2 < 49; card2++)
                {
                    for (int card3 = card2 + 1; card3 < 50; card3++)
                    {
                        for (int card4 = card3 + 1; card4 < 51; card4++)
                        {
                            for (int card5 = card4 + 1; card5 < 52; card5++)
                            {
                                // Each iteration of this loop visits a single outcome
                                totalOutcomesEnumerated++;
                            }
                        }
                    }
                }
            }
        }
    
        public void recalculateWitSkipList()
        {
            checkSkipList(numbers, lt.ExcludeNumbers);
            List<int[]> tmp = new List<int[]>();
            for (int j = 0; j < remainingCombinations.Count; j++)
            {
                int[] nums = remainingCombinations[j];
                bool contains = true;
                for (int i = 0; i < nums.Length; i++)
                {
                    if (!lt.ExcludeNumbers.Contains(nums[i]))
                    {
                        contains = false;
                    }
                }
                if (!contains)
                {
                    tmp.Add(nums);
                }
            }
            remainingCombinations = tmp;
            lt.RemainingCombinations = remainingCombinations.Count;
        }
        void addToPrint(int[] nums)
        {
            total++;
            //Console.WriteLine(asString(nums));
            int[] tmp = new int[nums.Length];
            for (int i = 0; i < nums.Length; i++)
            {
                tmp[i] = nums[i];
            }
            //there something wrong with c# it is not changing reference it stays the same, so I copied array each time
            allCombinations.Add(tmp);
            remainingCombinations.Add(tmp);
        }
           
        public string allCombinationsAsString()
        {
            return combinationsToString(allCombinations);
        }

        private string combinationsToString(List<int[]> combi)
        {
            StringBuilder sb = new StringBuilder();
            int cols = 0;
            bool firstTime = true;
//            int span = lt.Digits * 2 + lt.Digits - 1;
//            for (int i = 0; i < combi.Count; i++)
//            {
//
//                int[] comb = combi[i];
//                if (!firstTime)
//                {
//                    sb.Append('_');
//                }
//                cols++;
//                firstTime = false;
//                string ss = asString(comb);
//                sb.Append(ss);
//                if (cols != 5)
//                {
//                    int addition = span - ss.Length;
//                    for (int j = 0; j < addition; j++)
//                    {
//                        sb.Append('_');
//                    }
//                }
//                
//                if (cols == 5)
//                {
//                    sb.Append("\r\n");
//                    cols = 0;
//                    firstTime = true;
//                }
//
//
//            }

            var counter = 0;

            foreach (var comb in combi)
            {
                var numbers = asString(comb);
                
                sb.Append(numbers);
                
                if(counter == 4)
                {
                    sb.AppendLine();
                    counter = 0;
                    continue;
                }
                
                if(comb.Length == 5 && !comb.Any(n => n > 9))
                    sb.Append("\t");

                if (comb.Length == 4 && comb.Count(n => n > 9) >= 2)
                    sb.Append("\t");
                
                sb.Append("\t");
                counter++;
            }

            return sb.ToString();

        }
        public string combinationsAsString()
        {
            return combinationsToString(remainingCombinations);

        }
        private string asString(int[] nums)
        {
            StringBuilder sb = new StringBuilder();
            bool first = true;
            for (int i = 0; i < nums.Length; i++)
            {
                if (!first) { sb.Append("-"); }
                sb.Append(nums[i]);
                first = false;
            }
            return sb.ToString();
        }
        public void resetRemaining()
        {
            remainingCombinations = new List<int[]>();
            for (int i = 0; i < allCombinations.Count; i++)
            {
                remainingCombinations.Add(allCombinations[i]);
            }
            lt.RemainingCombinations = remainingCombinations.Count;
        }
    }
}
